#include "ProcTable.h"
#include <regex>

using namespace std;

ProcTable::ProcTable()
{
	this->curr_index = -1;
}

ProcTable::~ProcTable()
{
	std::map<PROCINDEX, ProcInfo*>::const_iterator it;

	for (it = index_table.begin(); it != index_table.end(); ++it)
	{
		ProcInfo* p = it->second;
		delete p;
		p = NULL;
	}

	//index_table.clear();
}

PROCINDEX ProcTable::InsertProc(const STRING proc_name)
{
	tr1::regex rx("[A-Za-z](([A-Za-z])|([0-9])|(#))*");

	// Check if variable already exist in VarTable.
	PROCINDEX proc_idx = this->GetProcIndex(proc_name);

	if (proc_idx == -1 && regex_match(proc_name.begin(), proc_name.end(), rx))
	{
		this->curr_index++; //next index

		ProcInfo* proc = new ProcInfo;
		proc->proc_index = this->curr_index;
		proc->proc_name = proc_name;
		proc->first_statement_number = -1;
		proc->last_statement_number = -1;

		this->index_table.insert(std::pair<PROCINDEX, ProcInfo*>(this->curr_index,proc));
		this->name_table.insert(std::pair<STRING, ProcInfo*>(proc_name,proc));
		
		proc_index_array.insert(curr_index);
		return this->curr_index;
	} else
	{
		return proc_idx;
	}
}

void ProcTable::SetProcStatementRange(const PROCINDEX index, 
	const INTEGER first_statement_number, 
	const INTEGER last_statement_number)
{
	if (first_statement_number <= 0 || 
		(first_statement_number > last_statement_number)) 
	{
		return;
	}

	if (index >= 0 && index <= this->curr_index)
	{
		ProcInfo* pInfo = this->index_table.find(index)->second;
		if (pInfo->first_statement_number == -1)
		{
			pInfo->first_statement_number = first_statement_number;
			pInfo->last_statement_number = last_statement_number;
		}
	}

	return;
}

INTEGER ProcTable::GetProcFirstStatementNumber(const PROCINDEX index)
{
	if (index >= 0 && index <= this->curr_index)
	{
		return this->index_table.find(index)->second->first_statement_number;
	} else
	{
		return -1;
	}
}

INTEGER ProcTable::GetProcLastStatementNumber(const PROCINDEX index)
{
	if (index >= 0 && index <= this->curr_index)
	{
		return this->index_table.find(index)->second->last_statement_number;
	} else
	{
		return -1;
	}
}

STRING ProcTable::GetProcName(const PROCINDEX index)
{
	if (index >= 0 && index <= this->curr_index)
	{
		return this->index_table.find(index)->second->proc_name;
	} else
	{
		return "";
	}
}

PROCINDEX ProcTable::GetProcIndex(const STRING proc_name)
{
	int has_proc_name = this->name_table.count(proc_name);
	
	if (has_proc_name == 1)
	{
		return this->name_table.find(proc_name)->second->proc_index;
	}

	return -1;
}

PROCINDEX_ARRAY ProcTable::GetAllProcIndex()
{
	return proc_index_array;
}

PROCINDEX ProcTable::GetProcIndex(const INTEGER statement_number)
{
	if (statement_number >= 1)
	{
		for (int i = 0; i <= this->curr_index; ++i)
		{
			INTEGER first = index_table.find(i)->second->first_statement_number;
			INTEGER last = index_table.find(i)->second->last_statement_number;

			// first <= statement_number <= last
			if (statement_number >= first && statement_number <= last)
			{
				return i;
			}
		}
	}

	return -1;
}

STRING_ARRAY ProcTable::GetAllProcNames()
{
	STRING_ARRAY string_array;

	for (VARINDEX i = 0; i <= this->curr_index; i++)
	{
		STRING proc_name = this->GetProcName(i);
		string_array.insert(proc_name);
	}

	return string_array;
}

INTEGER ProcTable::GetProcCount()
{
	return proc_index_array.size();
}